package org.xnat.xnatfs.filter;

import static org.mockito.Mockito.*;

import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.http.HttpSession;

import org.junit.Before;
import org.junit.Test;

import com.bradmcevoy.http.Auth;
import com.bradmcevoy.http.FilterChain;
import com.bradmcevoy.http.Request;
import com.bradmcevoy.http.Response;
import com.bradmcevoy.http.ServletRequest;
import com.bradmcevoy.http.ServletResponse;

public class TestAuthenticationFilter {
  private AuthenticationFilter filter;

  private Auth auth;
  private FilterChain chain;
  private ServletRequest request;
  private ServletResponse response;
  private HttpSession session;
  private OutputStream outputStream;

  @Before
  public void setUp () throws Exception {
    auth = mock ( Auth.class );
    chain = mock ( FilterChain.class );
    request = mock ( ServletRequest.class );
    response = mock ( ServletResponse.class );

    outputStream = mock ( OutputStream.class );
    when ( response.getOutputStream () ).thenReturn ( outputStream );

    session = mock ( HttpSession.class );
    when ( request.getSession () ).thenReturn ( session );

    filter = new AuthenticationFilter ();
  }

  @Test
  public void shouldEnsureCredentialsPresent () {
    when ( request.getAuthorization () ).thenReturn ( auth );

    filter.process ( chain, request, response );

    verify ( chain ).process ( request, response );
    verify ( session ).setAttribute ( "AuthenticationFilter_Auth", auth );
  }

  @Test
  public void shouldFallbackOnSessionAuth () {
    when ( request.getAuthorization () ).thenReturn ( null );
    when ( session.getAttribute ( "AuthenticationFilter_Auth" ) ).thenReturn ( auth );

    filter.process ( chain, request, response );

    verify ( chain ).process ( request, response );
  }

  @Test
  public void shouldPreventEmptyCredentials () {
    when ( request.getAuthorization () ).thenReturn ( null );
    when ( session.getAttribute ( "AuthenticationFilter_Auth" ) ).thenReturn ( null );

    filter.process ( chain, request, response );

    verify ( chain, never () ).process ( any ( Request.class ), any ( Response.class ) );
    verify ( response ).setStatus ( Response.Status.SC_UNAUTHORIZED );
  }

  @Test(expected = RuntimeException.class)
  public void shouldThrowResponseIOErrors () throws Exception {
    doThrow ( new IOException ( "fake error" ) ).when ( outputStream ).close ();
    when ( request.getAuthorization () ).thenReturn ( null );
    when ( session.getAttribute ( "AuthenticationFilter_Auth" ) ).thenReturn ( null );

    filter.process ( chain, request, response );
  }

}
